﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using DataAccessor.Exceptions;

namespace DataAccessor
{
    /// <summary>
    /// 数据访问接口
    /// </summary>
    public abstract partial class IDataAccessor
    {
        #region 正常
        /// <summary>
        /// 执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="statementName">TSQL配置节名称</param>
        /// <param name="paramValueArray">参数的值列表，必须和配置文件中定义的顺序一致。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet ExecuteDataSet(string statementName, params object[] paramValueArray)
        {
            return ExecuteDataSet(statementName, ToDictionary(statementName, paramValueArray));
        }
        /// <summary>
        /// 执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="statementName">TSQL配置节名称</param>
        /// <param name="paramValueDict">参数的值字典，Key村参数名，Value存参数的值。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet ExecuteDataSet(string statementName, Dictionary<string, object> paramValueDict)
        {
            DataSet result = null;
            var conn = CreateConnection();
            using (var cmd = CreateCommand())
            {
                try
                {
                    BuildCommand(cmd, conn, statementName, paramValueDict);
                    // var adapter = new SqlDataAdapter(cmd as SqlCommand);
                    var adapter = CreateAdapter(cmd);

                    result = new DataSet(statementName);
                    adapter.Fill(result);
                }
                catch (DbException ex)
                {

                    if (ReThrowExecuteException)
                    {
                        conn.Dispose();
                        throw;
                    }
                    else
                    {
                        CommandExecuteFailedException ce =
                            new CommandExecuteFailedException(cmd.CommandText, cmd.Connection.ConnectionString, paramValueDict, ex);
                        OnExecuteFailed(ce, this);
                        return null;
                    }
                }
            }

            CloseConnection(conn);
            return result;
        }

        /// <summary>
        /// 执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="commandText">SQL语句</param>
        /// <param name="commandParameters">命令的参数。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet ExecuteDataSetFromSQL(string commandText, params DbParameter[] commandParameters)
        {
            return ExecuteDataSetFromSQL(CommandType.Text, commandText, commandParameters);
        }

        /// <summary>
        /// 执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="commandType">命令类型</param>
        /// <param name="commandText">SQL语句</param>
        /// <param name="commandParameters">命令的参数。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet ExecuteDataSetFromSQL(CommandType commandType, string commandText, params DbParameter[] commandParameters)
        {
            DataSet result = null;
            var conn = CreateConnection();
            using (var cmd = CreateCommand())
            {
                try
                {
                    BuildCommand(cmd, commandType, conn, commandText, commandParameters);
                    DataAdapter adater = CreateAdapter(cmd);
                    result = new DataSet();
                    adater.Fill(result);
                }
                catch (DbException ex)
                {

                    if (ReThrowExecuteException)
                    {
                        conn.Dispose();
                        throw;
                    }
                    else
                    {
                        Dictionary<string, object> dictParams = new Dictionary<string, object>();
                        foreach (DbParameter param in commandParameters)
                        {
                            dictParams.Add(param.ParameterName, param.Value);
                        }
                        CommandExecuteFailedException ce =
                            new CommandExecuteFailedException(cmd.CommandText, cmd.Connection.ConnectionString, dictParams, ex);
                        OnExecuteFailed(ce, this);
                        return null;
                    }
                }
            }
            CloseConnection(conn);
            return result;
        }
        #endregion

        #region 事务
        /// <summary>
        /// 使用事务执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="trans">事务</param>
        /// <param name="statementName">TSQL配置节名称</param>
        /// <param name="paramValueArray">参数的值列表，必须和配置文件中定义的顺序一致。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet TransExecuteDataSet(DbTransaction trans, string statementName, params object[] paramValueArray)
        {
            return TransExecuteDataSet(trans, statementName, ToDictionary(statementName, paramValueArray));
        }
        /// <summary>
        /// 使用事务执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="connection">事务</param>
        /// <param name="statementName">TSQL配置节名称</param>
        /// <param name="paramValueDict">参数的值字典，Key村参数名，Value存参数的值。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet TransExecuteDataSet(DbTransaction trans, string statementName, Dictionary<string, object> paramValueDict)
        {
            // 如果没有指定事务，抛出异常
            if (trans == null)
            {
                throw new Exceptions.TransactionNullException(TRANSACTIONNULLEXCEPTION_MESSAGE);
            }

            using (var cmd = CreateCommand())
            {
                try
                {
                    BuildCommand(trans, cmd, trans.Connection, statementName, paramValueDict);
                    DbDataAdapter adapter = CreateAdapter(cmd);

                    DataSet result = new DataSet(statementName);
                    adapter.Fill(result);

                    return result;
                }
                catch (DbException ex)
                {
                    CommandExecuteFailedException ce =
                        new CommandExecuteFailedException(cmd.CommandText, trans.Connection.ConnectionString, paramValueDict, ex);
                    OnExecuteFailed(ce, this);

                    // 回滚事务
                    trans.Rollback();

                    // 关闭连接，释放事务
                    trans.Connection.Close();
                    trans.Connection.Dispose();
                    trans.Dispose();

                    if (ReThrowExecuteException)
                    {
                        // 处理异常
                        throw;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        /// <summary>
        /// 使用事务执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="trans">事务</param>
        /// <param name="commandType">命令类型</param>
        /// <param name="commandText">SQL语句</param>
        /// <param name="commandParameters">命令的参数。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet TransExecuteDataSetFromSQL(DbTransaction trans, string commandText, params DbParameter[] commandParameters)
        {
            return TransExecuteDataSetFromSQL(trans, commandText, commandParameters);
        }

        /// <summary>
        /// 使用事务执行 Transact-SQL 语句，返回一个数据集。
        /// </summary>
        /// <param name="trans">事务</param>
        /// <param name="commandType">命令类型</param>
        /// <param name="commandText">SQL语句</param>
        /// <param name="commandParameters">命令的参数。</param>
        /// <returns>DataSet数据集，如果执行失败且不重新抛出异常，则返回null</returns>
        public virtual DataSet TransExecuteDataSetFromSQL(DbTransaction trans, CommandType commandType, string commandText, params DbParameter[] commandParameters)
        {
            // 如果没有指定事务，抛出异常
            if (trans == null)
            {
                throw new Exceptions.TransactionNullException(TRANSACTIONNULLEXCEPTION_MESSAGE);
            }

            using (var cmd = CreateCommand())
            {
                try
                {
                    BuildCommand(trans, cmd, commandType, trans.Connection, commandText, commandParameters);
                    DbDataAdapter adapter = CreateAdapter(cmd);

                    DataSet result = new DataSet();
                    adapter.Fill(result);

                    return result;
                }
                catch (DbException ex)
                {
                    Dictionary<string, object> dictParams = new Dictionary<string, object>();
                    foreach (DbParameter param in commandParameters)
                    {
                        dictParams.Add(param.ParameterName, param.Value);
                    }
                    CommandExecuteFailedException ce =
                        new CommandExecuteFailedException(cmd.CommandText, trans.Connection.ConnectionString, dictParams, ex);
                    OnExecuteFailed(ce, this);

                    // 回滚事务
                    trans.Rollback();

                    // 关闭连接，释放事务
                    trans.Connection.Close();
                    trans.Connection.Dispose();
                    trans.Dispose();

                    if (ReThrowExecuteException)
                    {
                        // 处理异常
                        throw;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        #endregion

        #region 异步
        /// <summary>
        /// 异步执行 Transact-SQL 语句，返回异步结果。
        /// 可以自定义异步完成后的处理函数，也可以通过AsyncExecuteDataSetComplated事件获取执行结果。
        /// </summary>
        /// <param name="statementName">TSQL配置节名称</param>
        /// <param name="paramValueArray">参数的值列表，必须和配置文件中定义的顺序一致。</param>
        /// <returns>异步结果</returns>
        public virtual IAsyncResult AsyncExecuteDataSet(string statementName, params object[] paramValueArray)
        {
            return AsyncExecuteDataSet(statementName, ToDictionary(statementName, paramValueArray));
        }
        /// <summary>
        /// 异步执行 Transact-SQL 语句，返回异步结果。
        /// 可以自定义异步完成后的处理函数，也可以通过AsyncExecuteDataSetComplated事件获取执行结果。
        /// </summary>
        /// <param name="statementName">TSQL配置节名称</param>
        /// <param name="paramValueArray">参数的键值对数组，Key存储参数名，Value存参数的值。</param>
        /// <returns>异步结果</returns>
        public virtual IAsyncResult AsyncExecuteDataSet(string statementName, Dictionary<string, object> paramValueDict)
        {
            AsyncExecuteDelegate<DataSet> del = ExecuteDataSet;
            IAsyncResult iResult = del.BeginInvoke(statementName, paramValueDict, EndExecuteDataSet, del);

            return iResult;
        }

        /// <summary>
        /// 异步执行 Transact-SQL 语句，返回异步结果。
        /// </summary>
        /// <param name="commandType">命令类型</param>
        /// <param name="commandText">SQL语句</param>
        /// <param name="commandParameters">命令的参数。</param>
        /// <returns>异步结果</returns>
        public virtual IAsyncResult AsyncExecuteDataSetFromSQL(string commandText, params DbParameter[] commandParameters)
        {
            return AsyncExecuteDataSetFromSQL(CommandType.Text, commandText, commandParameters);
        }

        /// <summary>
        /// 异步执行 Transact-SQL 语句，返回异步结果。
        /// </summary>
        /// <param name="commandType">命令类型</param>
        /// <param name="commandText">SQL语句</param>
        /// <param name="commandParameters">命令的参数。</param>
        /// <returns>异步结果</returns>
        public virtual IAsyncResult AsyncExecuteDataSetFromSQL(CommandType commandType, string commandText, params DbParameter[] commandParameters)
        {
            AsyncExecuteCommandDelegate<DataSet> del = ExecuteDataSetFromSQL;
            IAsyncResult iResult = del.BeginInvoke(commandType, commandText, commandParameters, EndExecuteDataSet, del);

            return iResult;
        }

        /// <summary>
        /// 异步执行 Transact-SQL 语句的回调函数
        /// </summary>
        protected virtual void EndExecuteDataSet(IAsyncResult iResult)
        {
            if (iResult == null)
            {
                throw new ArgumentNullException(NULL_ASYNCEXECUTE_IRESULT_MESSAGE);
            }

            var del = iResult.AsyncState as AsyncExecuteDelegate<DataSet>;
            if (del == null)
            {
                throw new AsyncExecuteDelegateNullException(NULL_ASYNCEXECUTE_STATE_MESSAGE);
            }

            var result = del.EndInvoke(iResult);

            // 触发AsyncExecuteDataSetComplated事件
            OnAsyncExecuteDataSetComplated(result, this);
        }
        #endregion
    }
}
